package cn.mw.cmdb.service.impl;

import cn.mw.cmdb.entity.MwMacOuiInfo;
import cn.mw.cmdb.param.MacOuiExcelImportParam;
import cn.mw.cmdb.util.CMDBTool;
import cn.mw.cmdb.util.ExcelUtils;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.google.common.base.Strings;
import jakarta.servlet.http.HttpServletResponse;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
public class MacOuiExcelImportListener extends AnalysisEventListener<MacOuiExcelImportParam> {

    private HttpServletResponse response;

    private CmdbServiceManage cmdbServiceManage;

    /**
     * 文件名称
     */
    private String fileName;

    /**
     * 操作人员名称
     */
    private String operatorName;

    /**
     * 每隔100条存储数据库，然后清理list ，方便内存回收
     */
    private static final int BATCH_COUNT = 1000;

    private Map<String, String> macMap;

    private  ModelMacOuiServiceImpl modelMacOuiServiceImpl;

    /**
     * 解析成功的数据
     */
    List<MacOuiExcelImportParam> list;

    /**
     * 解析失败的数据
     */
    List<MacOuiExcelImportParam> failList = new ArrayList<>();

    public MacOuiExcelImportListener(HttpServletResponse response, String fileName, String operatorName, ModelMacOuiServiceImpl modelMacOuiServiceImpl,Map<String, String> macMap,List<MacOuiExcelImportParam> failList) {
        this.response = response;
        this.fileName = fileName;
        this.operatorName = operatorName;
        this.modelMacOuiServiceImpl = modelMacOuiServiceImpl;
        this.macMap = macMap;
        this.failList = failList;
    }

    /**
     * When analysis one row trigger invoke function.
     *
     * @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}
     * @param context
     */
    @SneakyThrows
    @Override
    public void invoke(MacOuiExcelImportParam data, AnalysisContext context) {
        list.add(data);
        if (list.size() >= BATCH_COUNT) {
            saveData();
            list.clear();
        }
    }

    /**
     * if have something to do after all analysis
     *
     * @param context
     */
    @SneakyThrows
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 这里也要保存数据，确保最后遗留的数据也存储到数据库
        if (list.size() > 0) {
            saveData();
            log.info("所有数据解析完成！");
        }
        if (failList.size() > 0) {
            excelFailData(failList);
            log.info("解析失败的所数据导出完成");
        }
    }

    /**
     * 导出错误数据至excel文件里
     *
     * @param failList 错误数据
     */
    private void excelFailData(List<MacOuiExcelImportParam> failList) {
        Set<String> includeColumnFiledNames = new HashSet<>();
        includeColumnFiledNames.add(CMDBTool.getFieldName(MacOuiExcelImportParam::getMac));
        includeColumnFiledNames.add(CMDBTool.getFieldName(MacOuiExcelImportParam::getShortName));
        includeColumnFiledNames.add(CMDBTool.getFieldName(MacOuiExcelImportParam::getVendor));
        includeColumnFiledNames.add(CMDBTool.getFieldName(MacOuiExcelImportParam::getCountry));
        includeColumnFiledNames.add(CMDBTool.getFieldName(MacOuiExcelImportParam::getAddress));
        includeColumnFiledNames.add(CMDBTool.getFieldName(MacOuiExcelImportParam::getErrorMsg));
        ExcelWriter excelWriter = null;
        String failFileName = fileName.indexOf(".") != -1 ? fileName.substring(0, fileName.indexOf(".")) : fileName;
        failFileName = "error_" + failFileName;
        try {
            excelWriter = ExcelUtils.getExcelWriter(failFileName, response, MacOuiExcelImportParam.class);
            WriteSheet sheet = EasyExcel.writerSheet(0, "sheet" + 0)
                    .includeColumnFiledNames(includeColumnFiledNames)
                    .build();
            excelWriter.write(failList, sheet);
            log.info("导出成功");
        } catch (IOException e) {
            log.error("导出失败{}", e);
        } finally {
            if (null != excelWriter) {
                excelWriter.finish();
            }
        }
    }

    /**
     * 保存数据
     */
    private void saveData() throws Exception {
        List<MwMacOuiInfo> mwMacOuiList = new ArrayList<>();
        //**** 数据校验 ****
        log.info("{}条数据，开始添加数据！", list.size());
        if (list.size() > 0) {
            for (MacOuiExcelImportParam importParam : list) {
                MwMacOuiInfo mwMacOuiInfo = new MwMacOuiInfo();
                mwMacOuiInfo = JSONObject.parseObject(JSONObject.toJSONString(importParam), MwMacOuiInfo.class);
                StringBuffer sbf = new StringBuffer();
                if (macMap != null && macMap.containsKey(importParam.getMac())) {
                    sbf.append("MAC特征已存在");
                    sbf.append(";");
                }

                if (!Strings.isNullOrEmpty(sbf.toString())) {
                    importParam.setErrorMsg(sbf.toString());
                    failList.add(importParam);
                    continue;
                }
                mwMacOuiList.add(mwMacOuiInfo);
            }
        }
        //**** 导入数据 ****
        if (CollectionUtils.isNotEmpty(mwMacOuiList)) {
            modelMacOuiServiceImpl.doBatchAdd(mwMacOuiList);
        }
        log.info("{}条数据，导入失败数据！", failList.size());
        log.info("{}条数据，添加数据结束！", mwMacOuiList.size());
    }
}
